package gstudio.mp3;

import gan.mp3.jmp123.decoder.Header;
import gan.mp3.jmp123.output.Audio;
import gan.mp3.jmp123.output.FFT;

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;

public class Mp3RuntimeWriteByte extends Audio {
	private float realIO[];
	private FFT fft;

	private int titleId = 0;
	private int startID = 0;
	private int endID = 0;
	private int canRecord = 0;

	private static final int Y0 = 1 << ((FFT.FFT_N_LOG + 3) << 1);
	private static final double logY0 = Math.log10(Y0);
	private int band, height, width;
	private int maxFs, deltax;
	private int[] xplot, lastPeak, lastY;
	private long lastTimeMillis;
	private Header heder;
	private static final int maxColums = 128;
	private Label label;
	private Display display;
	private String preName;
	private String outputDir;
	private MiniPlayerComposite playerComposite;
	private String inputMp3Path;
	private boolean writeMp3out;

	private String outputMp3Name;
	// 音频输出
	private Audio theAudio;

	// 放声音，然后切割文件，所以需要OutputDir等信息
	public Mp3RuntimeWriteByte(int sampleRate, Label l,
			MiniPlayerComposite playComposite, boolean writeMp3out) {
		this.writeMp3out = writeMp3out;

		label = l;
		display = playComposite.getDisplay();
		this.playerComposite = playComposite;

		realIO = new float[FFT.FFT_N];
		width = 396; // 频谱窗口396x140
		height = 140;
		band = 64; // 64段频谱
		fft = new FFT();
		maxFs = sampleRate >> 1;
		lastTimeMillis = System.currentTimeMillis();
		xplot = new int[maxColums + 1];
		lastPeak = new int[maxColums];
		lastY = new int[maxColums];
		setPlot(width);
		label.setText("[00:00] 00:00");
	}

	public void reloadInput() {
		inputMp3Path = playerComposite.getInputPath();
		preName = playerComposite.getOuputPreName();
		outputDir = playerComposite.getOuputDir();
	}

	@Override
	public boolean open(Header h, String artist) {
		this.heder = h;
		theAudio = new Audio();
		return theAudio.open(h, null);
	}

	@Override
	public int write(byte[] b, int size) {
		int len;
		// System.out.println(b.length+"@@@ "+size);

		// 1. 音频输出
		if ((len = theAudio.write(b, size)) == 0)
			return 0;

		int i, j;

		// 2. 获取PCM数据。如果是双声道，转换为单声道
		if (heder.getChannels() == 2) {
			for (i = 0; i < FFT.FFT_N; i++) {
				j = i << 2;
				// (左声道 + 右声道) / 2
				realIO[i] = (((b[j + 1] << 8) | (b[j] & 0xff))
						+ (b[j + 3] << 8) | (b[j + 2] & 0xff)) >> 1;
			}
		} else {
			for (i = 0; i < 512; i++) {
				j = i << 1;
				realIO[i] = ((b[j + 1] << 8) | (b[j] & 0xff));
			}
		}

		// 3. PCM变换到频域并取回模
		fft.getModulus(realIO);

		// 4. 绘制
		drawHistogram(realIO);

		return len;
	}

	/**
	 * 划分频段。
	 */
	private void setPlot(int width) {
		deltax = (width - band + 1) / band + 1;

		// fsband个频段落重新分划为band个频段，各频段宽度非线性划分。
		int fsband = FFT.FFT_N >> 1;
		if (maxFs > 20000) {
			float deltaFs = (float) maxFs / (FFT.FFT_N >> 1);
			fsband -= (maxFs - 20000) / deltaFs;
		}
		for (int i = 0; i <= band; i++) {
			xplot[i] = 0;
			xplot[i] = (int) (0.5 + Math.pow(fsband, (double) i / band));
			if (i > 0 && xplot[i] <= xplot[i - 1])
				xplot[i] = xplot[i - 1] + 1;
		}
	}

	private void drawHistogram(float[] amp) {
		float maxAmp;
		int i = 0, x = 0, y, xi, peaki;
		long t = System.currentTimeMillis();
		int speed = (int) (t - lastTimeMillis) / 40; // 峰值下落速度
		lastTimeMillis = t;

		int sum = 0;
		for (; i != band; i++, x += deltax) {
			// 查找当前频段的最大"幅值"
			maxAmp = 0;
			xi = xplot[i];
			y = xplot[i + 1];
			for (; xi < y; xi++) {
				if (amp[xi] > maxAmp)
					maxAmp = amp[xi];
			}

			y = (maxAmp > Y0) ? (int) ((Math.log10(maxAmp) - logY0) * 17) : 0;

			lastY[i] -= speed << 2;
			if (y < lastY[i]) {
				y = lastY[i];
				if (y < 0)
					y = 0;
			}
			lastY[i] = y;
			sum += y;

			if (y >= lastPeak[i]) {
				lastPeak[i] = y + 2;
			} else {
				// 使峰值匀速度下落
				peaki = lastPeak[i] - speed;
				if (peaki < 0)
					peaki = 0;
				lastPeak[i] = peaki;
				peaki = height - peaki;
			}
			y = height - y; // 坐标转换

		}

		endID = heder.getFrames() * 1152 - 50;
		int disct = endID - startID;

		// System.out.println(sum + " " + disct);

		if (sum > 100) {
			canRecord = 0;
		} else if (canRecord == 0 && disct > 50000) {
			canRecord = 1;

			new Thread() {
				public void run() {
					outputMp3Name = outputDir + "/" + preName + (++titleId)
							+ ".mp3";
					final int _startID = startID;
					startID = endID;
					if (writeMp3out) {
						new DoMp3CutFile().run(_startID, endID, inputMp3Path,
								outputMp3Name);
					}

					display.syncExec(new Runnable() {
						@Override
						public void run() {
							playerComposite.addSatzComp(_startID, endID,
									inputMp3Path, outputMp3Name);
						}
					});

				}

			}.start();
		}

		// 文字信息
		float dura = this.heder.getDuration();
		i = (int) (dura / 60);
		x = this.heder.getElapse();
		y = x / 60;
		final String strMsg = String.format("[%02d:%02d] %02d:%02d", i,
				(int) (dura - i * 60 + 0.5), y, x - y * 60);

		display.syncExec(new Runnable() {

			@Override
			public void run() {
				if (heder.getFrames() >= heder.getTrackFrames()) {
					playerComposite.doStop();
				}

				label.setText(strMsg);

			}
		});

	}
}
